package com.cgwx.tmservice.utils;

import com.cgwx.commonutils.DataTypeConvertUtils;
import com.cgwx.tmservice.config.DataConfig;
import com.cgwx.tmservice.entity.tm.TmInfoHisDate;
import com.cgwx.tmservice.entity.tm.TmParametersConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author GaoWei
 * @Date 2023/8/31 - 17:04
 */

// 遥测参数原码解析类
@Component
public class TmParseAnalysis {

    @Autowired
    private DataConfig dataConfig;

//    提取遥测识别码时的临时变量
    private String temp;
//    复波道
    private String fbd;
//    帧编号
    private String zbh;
//    帧类型码
    private String zlxm;
//    遥测参数配置相关参数
    private String tmName;
    private int tmStartPos;
    private int tmParamLength;
    private String tmCode;
    private int tmOriginalType;
    private int tmAnalyticType;
    private String tmAnalyticParam;
//    遥测原码值 遥测解析值
    private String originalValue;
    private String analyticValue;
//    符号位
    private int symbol = -1;
//    UTC时间
    private String utc_time_now = "0";
    String originalValueShow="";
    String originalValueTmp = this.originalValue;

    /**
     * 提取遥测识别信息区参数
     * @param StringBinTmFrame 纯遥测帧参数，二进制字符串；1792bit - > 224字节；原变量为StringBuffer，引用时改为String
     * @return 复波道_帧编号_帧类型码 字符串
     */
    public String getTmIdentifyInfo(String StringBinTmFrame){
//        复波道参数在遥测帧中所在的字节号（220）
        int fbd_byte = dataConfig.getFbd_byte() - 1;
//        提取遥测参数帧的识别区域（复波道、帧编号、帧类型码 共2字节，4字符，8bit）
        if (StringBinTmFrame.length() > fbd_byte * 8)
        {
//            纯遥测帧参数共224字节（H），遥测识别区为221字节 ~ 222字节，CRC为223~224字节（从1开始）
//            取复波道，帧编号所在字节
            this.temp = StringBinTmFrame.substring(fbd_byte * 8, fbd_byte * 8 + 8);
//            取复波道十进制值(3bit - > 十进制)
            this.fbd = DataTypeConvertUtils.Binary_to_Dec(this.temp.substring(dataConfig.getFbd_startBit(), dataConfig.getFbd_endBit()));
        }

//        帧编号在遥测帧中所在的字节号（220）
        int zbh_byte = dataConfig.getZbh_byte() - 1;
//        提取遥测参数帧的识别区域（复波道、帧编号、帧类型码 共2字节，4字符，8bit）
        if (StringBinTmFrame.length() > zbh_byte * 8)
        {
//            纯遥测帧参数共224字节（H），遥测识别区为221字节 ~ 222字节，CRC为223~224字节（从1开始）
//            取复波道，帧编号所在字节
            this.temp = StringBinTmFrame.substring(zbh_byte * 8, zbh_byte * 8 + 8);
//            取帧编号十进制值（5bit - > 十进制）
            this.zbh = DataTypeConvertUtils.Binary_to_Dec(this.temp.substring(dataConfig.getZbh_startBit(), dataConfig.getZbh_endBit()));
        }

//        帧类型码在遥测帧中所在的字节号（221）
        int zlxm_byte = dataConfig.getZlxm_byte() - 1;
//        提取遥测参数帧的识别区域（复波道、帧编号、帧类型码 共2字节，4字符，8bit）
        if (StringBinTmFrame.length() > zlxm_byte * 8)
        {
//            纯遥测帧参数共224字节（H），遥测识别区为221字节 ~ 222字节，CRC为223~224字节（从1开始）
//            取帧类型码所在字节
            this.temp = StringBinTmFrame.substring(zlxm_byte * 8, zlxm_byte * 8 + 8);
//            取帧类型码十进制值（4bit - > 十进制）
            this.zlxm = DataTypeConvertUtils.Binary_to_Dec(this.temp.substring(dataConfig.getZlxm_startBit(), dataConfig.getZlxm_endBit()));
        }

//        遥测识别区字符串（复波道_帧编号_帧类型码）
        return this.fbd + "_" + this.zbh + "_" + this.zlxm;
    }

    /**
     * 遥测参数分析，根据遥测参数配置信息，遥测参数二进制原码等信息，分析遥测解析方式
     * @param tmFrame_id 遥测帧id
     * @param tmIdentifyInfo 遥测帧识别码
     * @param tmParametersConfig 一个遥测参数配置信息，重点是一个
     * @param binTmFrame 遥测参数二进制原码 String，调用前为StringBuffer
     * @param utctime 遥测原码中解析出来的UTC时间
     * @param dataChannel 遥测数据通路
     */
    public TmInfoHisDate parseTmParameter(String tmFrame_id, String tmIdentifyInfo, TmParametersConfig tmParametersConfig, String binTmFrame, String utctime, String dataChannel)
    {
        this.symbol = -1;
//                tminfo_his_DATE 表一条记录对应的JavaBean
        TmInfoHisDate tmInfoHisDate = new TmInfoHisDate();

        try {
//            取出这个遥测配置项各参数内容
            this.tmName = tmParametersConfig.getTmName();
            this.tmStartPos = tmParametersConfig.getTmStartPos();
            this.tmParamLength = tmParametersConfig.getTmParamLength();
            this.tmCode = tmParametersConfig.getTmCode();
            this.tmOriginalType = tmParametersConfig.getTmOriginalType();
            this.tmAnalyticType = tmParametersConfig.getTmAnalyticType();
            this.tmAnalyticParam = tmParametersConfig.getTmAnalyticParam();
//            计算遥测工程值，message2WithoutDES长度为1792字符二进制原码，224字节纯遥测数据
//            表格配置正确的话，this.startBit + this.lengthBit最大为1760，下面的条件判断恒成立(即使只有一个参数)
            if ((binTmFrame.length() >= this.tmStartPos + this.tmParamLength) && (this.tmParamLength > 0))
            {
//                从遥测帧中取这个遥测原码（二进制）
                this.originalValue = binTmFrame.substring(this.tmStartPos, this.tmStartPos + this.tmParamLength);
//                计算遥测原码对应的遥测工程值
                this.analyticValue = DataTypeConvertUtils.TransForm_OriginalType(this.originalValue, this.tmOriginalType);
//                如果遥测原码以补码形式存储，确认其符号位
                if (this.tmOriginalType == 2)
                {
                    if (this.originalValue.length() % this.tmParamLength == 0)
                    {
                        this.symbol = (this.originalValue.charAt(0) == '1' ? 1 : 0);
                    } else {
                        this.symbol = 0;
                    }
                }
//                计算解析值
                this.analyticValue = DataTypeConvertUtils.TransForm_AnalyticType(this.analyticValue, this.tmAnalyticType, this.tmAnalyticParam, this.symbol);
//                确认解析值精度，只有在解析方式为“公式”时使用
                if (((this.tmAnalyticType == 2) || (this.tmAnalyticType == 9)) && (!this.analyticValue.equals("NaN")))
                {
//                    根据要求的小数位数，截取字符串参数
                    this.analyticValue = DataTypeConvertUtils.FormatDouble2(this.analyticValue, 2);
                }
//                确认解析值精度，只有在解析方式为“32位单精度浮点型”时使用
                if (this.tmAnalyticType == 8) {
                    this.analyticValue = DataTypeConvertUtils.FormatFloat(this.analyticValue, 2);
                }
//                将工程值转换为Double
                if (((this.tmAnalyticType == 1) || (this.tmAnalyticType == 2) || (this.tmAnalyticType == 8) || (this.tmAnalyticType == 9)) && (!this.analyticValue.equals("NaN")))
                {
                    Double.parseDouble(this.analyticValue);
                }
                this.originalValueShow = "";
                this.originalValueTmp = this.originalValue;
//                工程值处理方式不是 原码 或者 状态码（二进制）
                if ((this.tmAnalyticType != 0) && (this.tmAnalyticType != 5))
                {
//                    如果原码长度不是整字节数，则将其补齐为整字节，如果原码长度是整字节数，则不做处理Tmp即为Value
                    if (this.originalValue.length() % 8 != 0)
                    {
                        this.originalValueTmp = DataTypeConvertUtils.FullBinary(this.originalValue, this.originalValue.length() + 8 - this.originalValue.length() % 8);
                    }
//                    按字节，将二进制转换为字节显示
                    for (int i = 0; i < this.originalValueTmp.length() / 8; i++)
                    {
                        this.originalValueShow += DataTypeConvertUtils.Binary_to_Hex(this.originalValueTmp.substring(i * 8, i * 8 + 8));
                    }
                    this.originalValue = this.originalValueShow;
//                    加上标识符
                    this.originalValueShow += "(H)";
                }
                else
                {
//                    如果是原码显示或者二进制显示，则加上标识符
                    this.originalValueShow = (this.originalValue + "(b)");
                }

                tmInfoHisDate.setTmframeId(tmFrame_id);
                tmInfoHisDate.setTmframeIdentifiers(tmIdentifyInfo);
                tmInfoHisDate.setTmName(this.tmName);
                tmInfoHisDate.setOriginalValue(this.originalValueShow);
                tmInfoHisDate.setTmCode(this.tmCode);
                tmInfoHisDate.setTmOriginalType(this.tmOriginalType);
                tmInfoHisDate.setTmAnalyticType(this.tmAnalyticType);
                tmInfoHisDate.setTmAnalyticParam(this.tmAnalyticParam);
                tmInfoHisDate.setAnalyticValue(this.analyticValue);
                tmInfoHisDate.setUtctime(utctime);
                tmInfoHisDate.setDataChannel(dataChannel);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return tmInfoHisDate;
    }

    /**
     * 从二进制遥测原码中取出时间信息
     * @param binTmFrame 二进制遥测原码
     * @return 时间信息字符串（十进制）
     */
    public String getTmUtcTimeInfo(String binTmFrame)
    {

        try {
            this.tmStartPos = 64; //第8字节 开始为时间信息
            this.tmParamLength = 32; //占用4个字节，32bit
            this.tmOriginalType = 0; //无符号数
            this.tmAnalyticType = 1; //十进制
            this.tmAnalyticParam = ""; //无计算公式
            if ((binTmFrame.length() >= this.tmStartPos + this.tmParamLength))
            {
//                取出遥测数据中的时间信息的 整数秒 原码 2进制bin 4字节 32bit
                this.originalValue = binTmFrame.substring(this.tmStartPos, this.tmStartPos + this.tmParamLength);
//                计算工程值，无符号数直接返回
                this.analyticValue = DataTypeConvertUtils.TransForm_OriginalType(this.originalValue, this.tmOriginalType);
//                计算解析值
                this.analyticValue = DataTypeConvertUtils.TransForm_AnalyticType(this.analyticValue, this.tmAnalyticType, this.tmAnalyticParam, this.symbol);
//                utc值
                this.utc_time_now = this.analyticValue;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return this.utc_time_now;
    }
}
